很多应用场合对于空耗的要求很严格,比如长期无人照看的数据采集仪器,可穿戴设备等。其实很多 MCU 都有相应的低功耗模式,以此来降低设备运行时的功耗,进行裸机开发的时候就可以使用这些低功耗模式。但是现在我们要使用操作系统,因此操作系统对于低功耗的支持也显得尤为重要,这样硬件与软件相结合,可以进一步降低系统的功耗。这样开发也会方便很多,毕竟系统已经原生支持低功耗了,我们只需要按照系统的要求来做编写相应的应用层代码即可。 FreeRTOS 提供了一个叫做 Tickless 的低功耗模式,

  • STM32F1 低功耗模式
  • Tickless 模式详解

Tickless 模式详解

如何降低功耗?

一般的简单应用中处理器大量的时间都在处理空闲任务,所以我们就可以考虑当处理器处理空闲任务的时候就进入低功耗模式,当需要处理应用层代码的时候就将处理器从低功耗模式唤醒。 FreeRTOS 就是通过在处理器处理空闲任务的时候将处理器设置为低功耗模式来降低能耗。一般会在空闲任务的钩子函数中执行低功耗相关处理,比如设置处理器进入低功耗模式、关闭其他外设时钟、降低系统主频等等。

FreeRTOS 的系统时钟是由滴答定时器中断来提供的,系统时钟频率越高,那么滴答定时器中断频率也就越高。中断可以将 STM32F03 从睡眠模式中唤醒,周期性的滴答定时器中断就会导致 STM32F103 周期性的进入和退出睡眠模式。因此,如果滴答定时器中断频率太高的话会导致大量的能量和时间消耗在进出睡眠模式中,这样导致的结果就是低功耗模式的作用被大大的削弱.

FreeRTOS 特地提供了一个解决方法——Tickless 模式,当处理器进入空闲任务周期以后就关闭系统节拍中断(滴答定时器中断),只有当其他中断发生或者其他任务需要处理的时候处理器才会被从低功耗模式中唤醒。

为此我们将面临两个问题:
问题一:关闭系统节拍中断会导致系统节拍计数器停止,系统时钟就会停止。
问题二:如何保证下一个要运行的任务能被准确的唤醒?

Tickless 具体实现

1、宏 configUSE_TICKLESS_IDLE

要想使用 Tickless 模式,首先必须将 FreeRTOSConfig.h 中的宏 configUSE_TICKLESS_IDLE
设置为 1,代码如下:

1
#define configUSE_TICKLESS_IDLE 1 //1 启用低功耗 tickless 模式

2、宏 portSUPPRESS_TICKS_AND_SLEEP()

使 能 Tickless 模 式 以 后 当 下 面 两 种 情 况 都 出 现 的 时 候 FreeRTOS 内 核 就 会 调 用 宏
portSUPPRESS_TICKS_AND_SLEEP()来处理低功耗相关的工作。
● 空闲任务是唯一可运行的任务,因为其他所有的任务都处于阻塞态或者挂起态。
● 系统处于低功耗模式的时间至少大于 configEXPECTED_IDLE_TIME_BEFORE_SLEEP
个时钟节拍,宏 configEXPECTED_IDLE_TIME_BEFORE_SLEEP 默认在文件 FreeRTOS.h 中定
义为 2,我们可以在 FreeRTOSConfig.h 中重新定义,此宏必须大于 2!

3、宏 configPRE_SLEEP_PROCESSING ()和 configPOST_SLEEP_PROCESSING()

在真正的低功耗设计中不仅仅是将处理器设置到低功耗模式就行了,还需要做一些其他的处理,比如:

  • 将处理器降低到合适的频率,因为频率越低功耗越小,甚至可以在进入低功耗模式以后关闭系统时钟。

  • 修改时钟源,晶振的功耗肯定比处理器内部的时钟源高,进入低功耗模式以后可以切换到内部时钟源,比如 STM32 的内部 RC 振荡器。

  • 关闭其他外设时钟,比如 IO 口的时钟。

  • 关闭板子上其他功能模块电源,这个需要在产品硬件设计的时候就要处理好,比如可以通过 MOS 管来控制某个模块电源的开关,在处理器进入低功耗模式之前关闭这些模块的电源。